//5.作用域链(Scope chain)

/*
* 执行上下文，都有三个重要属性：
* 变量对象(Variable object，VO)
* 作用域链(Scope chain)
* this
* */

//作用域链:决定代码在执行时如何查找变量和函数

//核心作用：当访问一个变量时，JavaScript 引擎会沿着作用域链逐级向上查找，直到找到该变量或到达全局作用域

//组成:
//一系列变量对象VO组成的链式结构:
//当前执行上下文的活动对象AO ===> 层函数的活动对象AO ===> ...... ===>全局变量对象VO
/*
*具体构成:
* 第0位: 当前执行上下文的活动对象AO
* 第1位: 外层函数的活动对象AO
* 第2位: 更外层函数的活动对象AO
* ......
* 最后一位:全局变量对象VO
* */

//创建过程:
//函数定义时（静态作用域）
//函数在定义时就确定了其作用域链，而不是在调用时。
var newGlobalVar = 'newGlobalVar';
function newOuter(){
    var newOuterVar = 'newOuter';
    function inner(){
        var innerVar = 'inner';
        console.log(innerVar);  //当前AO
        console.log(newOuterVar);  //newOuterVar的AO
        console.log(newGlobalVar);  //全局VO
    }
    return inner;
}
var newFunc = newOuter();
// inner函数在定义时，作用域链就固定为: [innerAO,newOuterAO,globalVO]
newFunc();

//函数调用时
//当函数被调用时，会创建执行上下文，并构建完整的作用域链:
/*
* 1.复制函数的[[Scope]]内部属性(定义时确定)
* 2.创建当前活动对象AO并添加到作用域链前端
* 3.形成完整的作用域链
* */



//示例1：
var a = 1;
function outer(){
    var b = 2;
    function inner(){
        var c = 3;
        console.log(a + b + c);
    }
    inner();
}
outer();

let ScopeChain = {
    innerAO:{c:3},//当前AO
 // outerAo:{b:2,inner:<function>}, 外层AO
 // globalVo:{a:1,outer:<function>}  全局VO
}

//变量查找过程
/*
* c:在innerAO中找到  ===> 3
* b:在innerAO中未找到 ===> 在outerAO中找到 ====>2
* a:在innerAO中未找到 ===> 在outerAO未找到 ===> 在globalVO中找到 ===》 1
* */

//示例2：闭包的作用域链
var x = 10;
function createCounter(){
    var count = 0;
    return function (){
        count++;
        console.log("Count",count,"X",x);
        return count;
    }
}

var counter = createCounter();
counter();  //Count:1,x:10
counter();  //Count:2,x:10
/*
* counter函数执行时的作用域链
* Scope Chain = [
*  counterAO: { },
*  createCounterAO: { count: 2 },
*  globalVO:{ x:10, createCounter:<function>,counter:<function> }
* ]
* 即时createCounter已执行完毕，其AO仍然被counter函数的作用域链引用，形成闭包
* */

//示例3：多层嵌套
var global = 'g';
function level1(){
    var l1 = 'level2';
  function level2(){
      var l2 = "level2";
      function level3(){
          var l3 = 'level3';
          console.log(global,l1,l2,l3);
      }
      level3();
  }
  level2();
}
level1();

//level3函数的作用域链:
/*
* Scope Chain = {
*   level3AO = { l3:"level3" }
*   level2AO = { l2:"level2",level3:<function> }
*   level1AO = { l1:"level1",level2:<function>}
*   globalAO = { global:"g",level1:<function> }
* }
*
* */


//示例4：作用域链与with语句
//with语句会临时修改作用域链
var obj = { a:1,b:2};
var a = 100;
with(obj){
    console.log(a);  //1 (从obj中查找)
    console.log(b);  //2 (从obj中查找)
}
console.log(a); //100 (恢复正常作用域链)

/*
* Scope Chain = [
*    obj,        // with对象被添加到链首
*    currentAo,
*    outerAO,
*    globalVO
* ]
* */


//示例5：作用域链与catch语句
//catch语句也会修改作用域链

var e  = "outer";
try{
    throw "error message";
}catch (e) {
    //catch参数e被添加到作用域链首部
    console.log(e)   //"error message"
}
console.log(e);  //"outer" (恢复正常)

//示例6：作用域链的性能影响
//由于变量查找需要变量作用域链，优化:

//较慢: 需要变量作用域链
function slow(){
    for(var i = 0;i< 1000;i++){
        console.log(document); //每次都要查找document
    }
}

//较快: 局部缓存
function fast(){
    var doc = document; //一次查找
    for(var i = 0; i < 1000;i++){
        console.log(doc); //使用局部变量
    }
}

//作用域链的核心特性:
/*
* 1.静态作用域: 在函数定义时确定，而非调用时
* 2.链式结构: 由多个变量对象组成的链
* 3.查找机制: 从当前AO开始，逐级向外查找
* 4.闭包基础: 内层函数保持对外层函数AO的引用
* 5.性能影响:链越长,变量查找越慢
* */

//作用域链的作用:
/*
* 1.确定变量的可访问性
* 2.实现闭包功能
* 3.保证变量查找的有序性
* 4.维护函数的词法环境
* */
